﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace SemanticEx
{
	public static class RegexExtensions
	{
		public static IEnumerable<string> GetValues(this GroupCollection @this)
		{
			return @this.Cast<Group>().Skip(1)
				.Aggregate(Enumerable.Empty<string>(),
					(list, grp) => list.Concat(grp.Captures.Cast<Capture>().Select(x => x.Value)));
		}

		public static IEnumerable<string> GetValues(this Validation @this)
		{
			return @this.Match.Groups.GetValues();
		}

		public static Validator Validate(this Validator @this, string groupName, Func<string, bool> validation)
		{
			var validator = new Validator(@this);
			validator.AddValidation(groupName, validation);
			return validator;
		}

		public static Validator Validate(this Regex @this, string groupName, Func<string, bool> validation)
		{
			return new Validator(@this).Validate(groupName, validation);
		}

		public static Validation Validate(this Match @this, string groupName, Func<string, bool> validation)
		{
			var group = @this.Groups[groupName];
			var isValid = @this.Success;
			try
			{
				foreach (Capture capture in group.Captures)
				{
					isValid &= validation(capture.Value);
				}
			}
			catch (Exception ex)
			{
				isValid = false;
				throw ex;
			}
			return new Validation(@this, isValid);
		}

		/// <summary>
		/// Accepts a validation expression of the type "{groupName}=>{boolean predicate}".
		/// {groupName} is the only variable allowed in the boolean expression.
		/// </summary>
		public static Validator Validate(this Regex @this, string validationExpression)
		{
			var info = RegexValidationParser.Parse(@this, validationExpression);
			return @this.Validate(info.GroupName, info.Validation);
		}

		/// <summary>
		/// Accepts a validation expression of the type "{groupName}=>{boolean predicate}".
		/// {groupName} is the only variable allowed in the boolean expression.
		/// </summary>
		public static Validator Validate(this Validator @this, string validationExpression)
		{
			var info = RegexValidationParser.Parse(@this.Regex, validationExpression);
			return @this.Validate(info.GroupName, info.Validation);
		}

		public static Validator IsInRange(this Validator @this, string groupName, int inclusiveMin, int exclusiveMax)
		{
			return @this.Validate(groupName, x => (inclusiveMin <= Convert.ToInt32(x)) && (Convert.ToInt32(x) < exclusiveMax));
		}

		public static Validator IsInRange(this Regex @this, string groupName, int inclusiveMin, int exclusiveMax)
		{
			return @this.Validate(groupName, x => (inclusiveMin <= Convert.ToInt32(x)) && (Convert.ToInt32(x) < exclusiveMax));
		}
	}
}